﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BeanboxSoftware.BeanMap
{
  public partial class Map<K, V> : Internal.MapBase<Func<K, V>, V, K, V>, IMap<K, V>
  {
    public Map()
    {
    }

    public Map(Map<K, V> copy)
    {
      foreach (var kv in copy.KeyValues)
      {
        this[kv.Key] = kv.Value;
      }
    }

    public Map(IEnumerable<V> values, Func<V, K> keyGen)
    {
      foreach (var item in values)
      {
        this[keyGen(item)] = item;
      }
    }

    protected void SafeSet(K key, V value)
    {
      var data = SafeGet();
      data[key] = value;
    }

    public V this[K key]
    {
      get
      {
        if (!ContainsKey(key))
        {
          return HandleKeyNotFound(gen => gen(key), v => this[key] = v, () => new object[] { key });
        }

        return RetrieveDataHandle()[key];
      }
      set
      {
        SafeSet(key, value);
      }
    }

    public V Get(K key)
    {
      return this[key];
    }

    public override int Count
    {
      get { return RetrieveDataHandle().Count; }
    }

    public override bool TryGetValue(K key, out V value)
    {
      return RetrieveDataHandle().TryGetValue(key, out value);
    }

    public bool Contains(KeyValuePair<K, V> kvp)
    {
      return ContainsKey(kvp.Key) && EqualityComparer<V>.Default.Equals(this[kvp.Key], kvp.Value);
    }

    public bool Remove(KeyValuePair<K, V> kvp)
    {
      if (Contains(kvp))
      {
        return Remove(kvp.Key);
      }

      return false;
    }

    public void Add(KeyValuePair<K, V> kvp)
    {
      Add(kvp.Key, kvp.Value);
    }

    public void Add(K key, V value)
    {
      if (ContainsKey(key))
      {
        throw new ArgumentException("Key already exists in the map");
      }

      this[key] = value;
    }

    protected override V IndexerGet(K key)
    {
      return this[key];
    }

    protected override void IndexerSet(K key, V value)
    {
      this[key] = value;
    }

    public IEnumerable<KeyValuePair<K, V>> KeyValues
    {
      get
      {
        return RetrieveDataHandle();
      }
    }

    public IEnumerable<K> Keys
    {
      get
      {
        return ((IDictionary<K, V>)this).Keys;
      }
    }

    public IEnumerable<V> Values
    {
      get
      {
        return ((IDictionary<K, V>)this).Values;
      }
    }
  }
}
